//

package main

import (
	"flag"
	"fmt"
	"log"
	"net"
	"time"
)

const (
	version string = "0.0.1"
)

var (
	server string
	room   string
)

func main() {
	flag.StringVar(&server, "s", "xxx.example.com:8266", "server address")
	flag.StringVar(&room, "r", "yt8qik3&C&Wg", "room id")
	flag.Parse()

	log.Println("Version", version)
	log.Println("Server address:", server)
	log.Println("Room ID:", room)

	addr, err := net.ResolveUDPAddr("udp", server)
	if err != nil {
		fmt.Println("[ERROR] ResolveUDPAddr():", err)
		return
	}

	conn, err := net.DialUDP("udp", nil, addr)
	if err != nil {
		fmt.Println("[ERROR] DialUDP()", err)
		return
	}
	localUDPAddr := conn.LocalAddr().(*net.UDPAddr)

	n, err := conn.Write([]byte(room))
	if err != nil {
		log.Println("[ERROR] Write()", err)
		return
	}
	log.Printf("TO server SENT %s ", room)

	response := make([]byte, 64)
	n, _, err = conn.ReadFromUDP(response)
	if err != nil {
		log.Println("[ERROR] ReadFromUDP()", err)
		return
	}
	log.Printf("FROM server RECEIVED %s", string(response[:n]))

	err = conn.Close()
	if err != nil {
		log.Println("[ERROR] Close()", err)
		return
	}
	log.Println("Connection to server CLOSED")

	peerUDPAddr, err := net.ResolveUDPAddr("udp", string(response[:n]))
	if err != nil {
		log.Println(err)
		return
	}
	punching(localUDPAddr, peerUDPAddr)
}

func punching(laddr *net.UDPAddr, raddr *net.UDPAddr) {
	log.Println("Start punching...")
	log.Printf("local: %v  remote: %v", laddr, raddr)

	conn, err := net.DialUDP("udp", laddr, raddr)
	if err != nil {
		log.Println("[ERROR] DialUDP()", err)
		return
	}
	defer conn.Close()

	msg := "hello"
	_, err = conn.Write([]byte(msg))
	if err != nil {
		log.Println("[ERROR] Write()", err)
		return
	}
	log.Println("TO peer SENT", msg)

	go func() {
		for {
			msg = fmt.Sprintf("%d", time.Now().UnixNano())
			_, err := conn.Write([]byte(msg))
			if err != nil {
				log.Println("[ERROR] Write()", err)
				return
			}
			log.Printf("TO peer SENT %s", msg)
			time.Sleep(time.Second * 5)
		}
	}()

	buf := make([]byte, 64)
	for {
		n, _, err := conn.ReadFromUDP(buf)
		if err != nil {
			log.Println("[ERROR] Read()", err)
			return
		}
		log.Printf("FROM peer RECEIVED %s", string(buf[:n]))
	}
}
